/*
 * 24/10/2011 - 03:48
 */
package org.nettyflux.jsonrpc;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.nettyflux.communicator.RemoteHost;
import org.nettyflux.mailbox.MailBox;
import org.nettyflux.netmessages.NetworkMessage;
import org.nettyflux.netmessages.SendCommand;
import org.nettyflux.remote.SkeletonRegistry;
import org.nettyflux.remote.SkeletonStrategy;

/**
 * @author Victor Williams Stafusa da Silva
 */
public class SimpleJsonSkeletonStrategy implements SkeletonStrategy {

    private final JsonMarshal marshal;

    public SimpleJsonSkeletonStrategy() {
        this(new JsonMarshal());
    }

    public SimpleJsonSkeletonStrategy(JsonMarshal marshal) {
        this.marshal = marshal;
    }

    @Override
    public void handle(SkeletonRegistry registry, MailBox<NetworkMessage> mailbox, RemoteHost host, byte[] data) {
        Command c;
        try {
            c = marshal.read(Command.class, data);
        } catch (IOException e) {
            return;
        }

        Object entity = registry.find(c.getObjectName());
        if (entity == null) return;

        Method theMethod = null;
        for (Class<?> iface : entity.getClass().getInterfaces()) {
            for (Method m : iface.getMethods()) {
                if (m.toGenericString().equals(c.getOperation())) {
                    theMethod = m;
                    break;
                }
            }
        }

        CommandReply reply;
        if (theMethod == null) {
            reply = CommandReply.createForException(c, new IllegalArgumentException());
        } else {
            try {
                Object result = theMethod.invoke(entity, c.getParameters());
                reply = CommandReply.createFor(c, result);
            } catch (InvocationTargetException e) {
                reply = CommandReply.createForException(c, e.getCause());
            } catch (IllegalAccessException e) {
                throw new AssertionError(e);
            }
        }

        try {
            mailbox.postMessage(SendCommand.create(host, marshal.write(reply)));
        } catch (IOException ex) {
            // TO DO: How to handle this properly?
            throw new RuntimeException(ex);
        }
    }
}
